cmake_minimum_required(VERSION 3.12)
project(mpi_tests LANGUAGES C CXX Fortran)

###########################################################################
# 查找MPICH（Intel编译器版本）的编译器包装器
###########################################################################
find_program(MPI_C_COMPILER NAMES mpicc DOC "MPICH C compiler wrapper (Intel)")
find_program(MPI_CXX_COMPILER NAMES mpicxx DOC "MPICH CXX compiler wrapper (Intel)")
find_program(MPI_Fortran_COMPILER NAMES mpif90 DOC "MPICH Fortran compiler wrapper (Intel)")

# 强制设置编译器（Intel版本MPICH）
set(CMAKE_C_COMPILER ${MPI_C_COMPILER} CACHE FILEPATH "MPICH C compiler (Intel)" FORCE)
set(CMAKE_CXX_COMPILER ${MPI_CXX_COMPILER} CACHE FILEPATH "MPICH CXX compiler (Intel)" FORCE)
set(CMAKE_Fortran_COMPILER ${MPI_Fortran_COMPILER} CACHE FILEPATH "MPICH Fortran compiler (Intel)" FORCE)

###########################################################################
# 查找MPICH组件
###########################################################################
find_package(MPI REQUIRED COMPONENTS C CXX Fortran)
message(STATUS "MPICH (Intel) Path: ${MPI_CXX_LIBRARIES}")

###########################################################################
# 设置C++标准
###########################################################################
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

###########################################################################
# 基础配置
###########################################################################
set(CMAKE_Fortran_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/modules)
include_directories(${CMAKE_Fortran_MODULE_DIRECTORY})

if(POLICY CMP0079)
    cmake_policy(SET CMP0079 NEW)
endif()

###########################################################################
# 编译选项函数（修正Intel编译器选项）
###########################################################################
function(set_mpi_compile_options TARGET_NAME LANGUAGE)
    if(LANGUAGE STREQUAL "Fortran")
        if(CMAKE_Fortran_COMPILER_ID MATCHES "GNU")
            target_compile_options(${TARGET_NAME} PRIVATE
                -O3
                -Wall
                -Wno-maybe-uninitialized
                -Wno-tabs
                -ffree-line-length-none
                -fimplicit-none
                -Wno-error
            )
        elseif(CMAKE_Fortran_COMPILER_ID MATCHES "Intel")
            target_compile_options(${TARGET_NAME} PRIVATE
                -O3
                -Wall  # 修正：Intel支持的警告选项
                -diag-disable 5268,7712
            )
        endif()
    elseif(LANGUAGE MATCHES "CXX|C")
        if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
            target_compile_options(${TARGET_NAME} PRIVATE
                -O3
                -Wall
                -Wextra
                $<$<COMPILE_LANGUAGE:CXX>:-Weffc++>
                $<$<COMPILE_LANGUAGE:CXX>:-Wno-non-virtual-dtor>
            )
        elseif(CMAKE_CXX_COMPILER_ID MATCHES "Intel")
            target_compile_options(${TARGET_NAME} PRIVATE
                -O3
                -Wall  # 修正：Intel支持的警告选项
                -diag-disable 177,383
            )
        endif()
    endif()
endfunction()

###########################################################################
# MPI目标生成函数
###########################################################################
function(add_mpi_fortran_executable TARGET_NAME)
    add_executable(${TARGET_NAME} ${ARGN})
    set_target_properties(${TARGET_NAME} PROPERTIES COMPILE_OPTIONS "")
    target_link_libraries(${TARGET_NAME} PRIVATE MPI::MPI_Fortran)
    set_mpi_compile_options(${TARGET_NAME} "Fortran")
endfunction()

function(add_mpi_cpp_executable TARGET_NAME)
    add_executable(${TARGET_NAME} ${ARGN})
    target_link_libraries(${TARGET_NAME} PRIVATE MPI::MPI_CXX MPI::MPI_C)
    set_mpi_compile_options(${TARGET_NAME} "CXX")
endfunction()

function(add_mpi_mixed_executable TARGET_NAME)
    set(FORTRAN_SOURCES)
    set(C_SOURCES)
    foreach(src ${ARGN})
        if(src MATCHES "\\.(f90|F90|f95|F95)$")
            list(APPEND FORTRAN_SOURCES ${src})
        elseif(src MATCHES "\\.(c|C|cpp|CPP)$")
            list(APPEND C_SOURCES ${src})
        endif()
    endforeach()

    add_executable(${TARGET_NAME} ${FORTRAN_SOURCES} ${C_SOURCES})

    target_link_libraries(${TARGET_NAME} PRIVATE
        MPI::MPI_Fortran
        MPI::MPI_C
        MPI::MPI_CXX
    )

    target_include_directories(${TARGET_NAME} PRIVATE
        ${CMAKE_Fortran_MODULE_DIRECTORY}
    )

    if(FORTRAN_SOURCES)
        set_source_files_properties(${FORTRAN_SOURCES} PROPERTIES LANGUAGE Fortran)
        if(CMAKE_Fortran_COMPILER_ID MATCHES "GNU")
            set_property(SOURCE ${FORTRAN_SOURCES} APPEND PROPERTY COMPILE_OPTIONS
                -O3 -Wall -Wno-maybe-uninitialized -Wno-tabs -ffree-line-length-none -fimplicit-none -Wno-error
            )
        elseif(CMAKE_Fortran_COMPILER_ID MATCHES "Intel")
            set_property(SOURCE ${FORTRAN_SOURCES} APPEND PROPERTY COMPILE_OPTIONS
                -O3 -Wall -diag-disable 5268,7712  # 修正：替换-warn all
            )
        endif()
    endif()

    if(C_SOURCES)
        set_source_files_properties(${C_SOURCES} PROPERTIES LANGUAGE C)
        if(CMAKE_C_COMPILER_ID MATCHES "GNU")
            set_property(SOURCE ${C_SOURCES} APPEND PROPERTY COMPILE_OPTIONS
                -O3 -Wall -Wextra
            )
        elseif(CMAKE_C_COMPILER_ID MATCHES "Intel")
            set_property(SOURCE ${C_SOURCES} APPEND PROPERTY COMPILE_OPTIONS
                -O3 -Wall -diag-disable 177,383  # 修正：替换-warn all
            )
        endif()
    endif()
endfunction()

###########################################################################
# 测试目标
###########################################################################
# C++测试
add_mpi_cpp_executable(test_mpi_cpp test_mpi.cpp)
add_mpi_cpp_executable(mpi_basic_cpp mpi_basic.cpp)
add_mpi_cpp_executable(mpi_sendrecv_demo mpi_sendrecv_demo.cpp)
add_mpi_cpp_executable(mpi_split_comm_index mpi_split_comm_index.cpp)
add_mpi_cpp_executable(test_all_mpi_cpp test_all_mpi.cpp)

# Fortran测试
add_mpi_fortran_executable(test_mpi_fortran test_mpi.F90)
add_mpi_fortran_executable(mpi_max_broadcast mpi_max_broadcast.F90)
add_mpi_fortran_executable(mpi_comm_split mpi_comm_split.F90)
add_mpi_fortran_executable(mpi_basic mpi_basic.F90)

# 混合语言测试
add_mpi_mixed_executable(mixed_c_fortran
    mixed_c_fortran.c
    mixed_c_fortran.f90
)
add_mpi_mixed_executable(mixed_fortran_c
    mixed_fortran_c.c
    mixed_fortran_c.f90
)

###########################################################################
# 复制脚本和运行说明
###########################################################################
configure_file(
    ${CMAKE_CURRENT_SOURCE_DIR}/run_all_mpi_tests.sh
    ${CMAKE_BINARY_DIR}/run_all_mpi_tests.sh
    COPYONLY
)
configure_file(
    ${CMAKE_CURRENT_SOURCE_DIR}/check_mpi_coverage.py
    ${CMAKE_BINARY_DIR}/check_mpi_coverage.py
    COPYONLY
)

# 运行提示（Intel版本MPICH）
message(STATUS "==================================================")
message(STATUS "MPICH (Intel) 环境配置:")
message(STATUS "  1. 清理环境: module purge && unset LD_LIBRARY_PATH CPATH PKG_CONFIG_PATH")
message(STATUS "  2. 加载Intel编译器和MPICH: module load compiler/intel/2017.5.239 mpi/mpich/3.3.2/intel")
message(STATUS "  3. 验证: mpirun --version")
message(STATUS "编译命令:")
message(STATUS "  mkdir -p build-mpich && cd build-mpich")
message(STATUS "  cmake ..")
message(STATUS "  make -j32")
message(STATUS "直接运行命令:")
message(STATUS "  mpirun -n 2 ./test_mpi_fortran")
message(STATUS "增加mpitracer库拦截运行命令:")
message(STATUS "    mpiexec -genv LD_PRELOAD=mpitracer.so:/public/software/mpi/mpich/intel/3.3.2-2017/lib/libmpi.so.12.1.8 -np 4 ./test_mpi_cpp")
message(STATUS "==================================================")